package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.dao.*;
import com.sc.nft.dto.UserFirstBuyDTO;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.OrderDetailsDTO;
import com.sc.nft.entity.vo.CreateOrderVO;
import com.sc.nft.entity.vo.OrderDetailsVO;
import com.sc.nft.entity.vo.RoughStoneOrderVO;
import com.sc.nft.enums.*;
import com.sc.nft.exception.GlobalException;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.helper.MessageQueueHelper;
import com.sc.nft.pool.UserPool;
import com.sc.nft.service.ProductStockService;
import com.sc.nft.service.RoughStoneOrderService;
import com.sc.nft.service.UserCollectionService;
import com.sc.nft.sup.ErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * 原始订单表服务接口实现
 *
 * @author zxy
 * @description 汇付相关
 * @since 2023-08-14 16:40:43
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class RoughStoneOrderServiceImpl implements RoughStoneOrderService {
    private final RoughStoneOrderDao roughStoneOrderDao;
    private final UserWalletDao userWalletDao;
    private final UserCollectionService userCollectionService;
    private final ExpenditureRecordDao expenditureRecordDao;
    private final DigitalCollectionDao digitalCollectionDao;
    private final ProductStockService productStockService;
    private final StaticDataDao staticDataDao;
    private final UserInfoDao userInfoDao;
    private final MessageQueueHelper messageQueueHelper;
    private final PayOrderDao payOrderDao;

    @Override
    public void paySuccess(RoughStoneOrder order)  {
        if (ObjectUtil.isNull(order) || order.getStatus() != OrderStatusEnum.WAIT_PAY) {
            throw new GlobalRunTimeException("未找到支付订单");
        }
        DateTime now = DateTime.now();
        order.setPayTime(now);
        order.setStatus(OrderStatusEnum.PAYMENT);
        order.updateById();

        productStockService.subStock(order.getProductId(), order.getCollectionId(), order.getCount(), order.getUserId(), CommodityType.SALVAGE_COLLECTION);
        PayOrder byOrderNo = payOrderDao.getByOrderNo(order.getOrderNo());
        boolean isOpen = true;
        Long boxId = null;
        String boxTitle = null;
        String boxImage = null;
        Long collectionId = order.getCollectionId();
        for (int i = 0; i < order.getCount(); i++) {
            DigitalCollection digitalCollection = digitalCollectionDao.getById(collectionId);
            UserCollection userCollection = userCollectionService.addCollection(order.getUserId(), null, digitalCollection.getId(), IdUtil.getSnowflakeNextIdStr(), digitalCollection.getCreationContent(), digitalCollection.getLevel(), digitalCollection.getFirstTitle(), digitalCollection.getUserCreatorId(), ReceivedCollectionType.ROUGH_STONE, boxId, boxTitle, boxImage, isOpen, order.getProductId(), order.getId(), 0L, order.getProductPrice().divide(BigDecimal.valueOf(order.getCount())), 0, null, null, AddCollectionEnum.STAIR,null,null,false);
            //藏品流转表记录
            CollectionCirculatingRecord collectionCirculatingRecord = new CollectionCirculatingRecord();
            collectionCirculatingRecord.setUserId(order.getUserId());
            collectionCirculatingRecord.setCollectionId(digitalCollection.getId());
            collectionCirculatingRecord.setCommodityType(CommodityType.PRODUCT);
            collectionCirculatingRecord.setTypeClassify(order.getTypeClassify());
            collectionCirculatingRecord.setReceivedCollectionType(ReceivedCollectionType.BUY);
            collectionCirculatingRecord.setToUserCollection(userCollection.getId());
            collectionCirculatingRecord.setOrderId(order.getId());
            collectionCirculatingRecord.insert();
        }

        //账单明细记录
        UserWallet userWallet = userWalletDao.getByUserId(order.getUserId());
        if (byOrderNo.getChannel()!=PayChannelEnum.NATIVE) {
            ExpenditureRecord expenditureRecord = new ExpenditureRecord();
            expenditureRecord.setUserId(order.getUserId());
            expenditureRecord.setAmount(order.getProductPrice());
            expenditureRecord.setCharge(BigDecimal.ZERO);
            expenditureRecord.setRealAmount(BigDecimal.ZERO);
            expenditureRecord.setType(ExpenditureRecordTypeEnum.EXPENDITURE);
            expenditureRecord.setBeforeBalance(userWallet.getBalance());
            expenditureRecord.setAfterBalance(userWallet.getBalance());
            expenditureRecord.setOrderId(order.getId());
            expenditureRecordDao.insert(expenditureRecord);
        }
        UserInfo userInfo = userInfoDao.getById(order.getUserId());
        if (!userInfo.getIsValid()) {
            userInfoDao.setIsValid(userInfo.getId());
            messageQueueHelper.sendMessage(MessageTopic.USER_FIRST_BUY, new UserFirstBuyDTO(userInfo.getId(), order.getId(), 3));

        }
//        SaasTaskBurialPointDTO saasTaskBurialPointDTO = new SaasTaskBurialPointDTO();
//        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
//            @Override
//            public void afterCommit() {
//                messageQueueHelper.sendMessage(MessageTopic.DISK_TAKER, saasTaskBurialPointDTO.wallet(order.getUserId(), SaasTaskTypeEnum.PURCHASE_OF_DESIGNATED_COLLECTION, BigDecimal.ONE, 1, null));
//                messageQueueHelper.sendMessage(MessageTopic.DISK_TAKER, saasTaskBurialPointDTO.wallet(order.getUserId(), SaasTaskTypeEnum.INVITATION_TO_PURCHASE_SPECIFIED_COLLECTIONS, BigDecimal.ONE, 1, null));
//            }
//        });
    }

    @Override
    public Page<RoughStoneOrder> orderPage(UserInfo userInfo, OrderStatusEnum orderStatus, Integer pageNo, Integer pageSize) {
        return roughStoneOrderDao.orderPage(userInfo.getId(), orderStatus, pageNo, pageSize);
    }

    @Override
    public CreateOrderVO findRoughStoneOrderByOrderNo(String orderNo) {
        RoughStoneOrder order = roughStoneOrderDao.getByOrderNo(orderNo);

        if (ObjectUtil.isEmpty(order)) {
            throw new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND);
        }

        OrderStatusEnum status = order.getStatus();
        if (status.getCode() != OrderStatusEnum.WAIT_PAY.getCode()) {
            throw new GlobalRunTimeException(ErrorCode.THE_ORDER_IS_NOT_PAID);
        }
        if (UserPool.getUser().getId().intValue() != order.getUserId().intValue()) {
            throw new GlobalRunTimeException(ErrorCode.PARAM_ERROR);
        }

        CreateOrderVO createOrderVO = new CreateOrderVO();

        long time = order.getCloseTime().getTime();
        long nowTime = DateTime.now().getTime();

        time = time - nowTime;
        String purchaseNotes = staticDataDao.getByType("purchase_notes").getValue();
        createOrderVO.setOrderId(order.getId());
        createOrderVO.setPurchaseNotes(purchaseNotes);
        createOrderVO.setOffsetTime(time);
        createOrderVO.setProductNum(order.getProductPrice().stripTrailingZeros().toPlainString());
        createOrderVO.setOrderNo(order.getOrderNo());
        createOrderVO.setNowDate(DateUtil.now());
        createOrderVO.setExpirationTime(DateUtil.offsetMinute(new Date(), 3));
        return createOrderVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void closeOrder(Long id) throws GlobalException {
        RoughStoneOrder order = roughStoneOrderDao.getById(id);
        if (ObjectUtil.isEmpty(order)) {
            throw new GlobalException(ErrorCode.ORDER_NOT_FOUND);
        }

        Assert.isTrue(order.getUserId().longValue() == UserPool.getUser().getId().longValue(), () -> new GlobalException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isFalse(order.getStatus() == OrderStatusEnum.PAYMENT, () -> new GlobalException(ErrorCode.ORDER_PAID));
        if (order.getStatus() == OrderStatusEnum.CLOSE) {
            throw new GlobalException(ErrorCode.ORDER_CLOSED);
        }
        Assert.isTrue(roughStoneOrderDao.closeOrder(id), () -> new GlobalRunTimeException("关闭订单失败"));

        productStockService.SubFrozenCount(order.getProductId(), order.getCollectionId(), order.getCount());
    }

    @Override
    public OrderDetailsVO getRoughStoneOrderDetailsById(Long id) {
        OrderDetailsDTO orderDetailsDTO = roughStoneOrderDao.getOrderDetailsById(id);
        int status = orderDetailsDTO.getStatus();

        OrderDetailsVO orderDetailsVO = BeanUtil.toBean(orderDetailsDTO, OrderDetailsVO.class);
        if (OrderStatusEnum.CLOSE.getCode() == status) {
            orderDetailsVO.setOrderStatus("未支付");
            orderDetailsVO.setPayMethod("超时结束");

        } else if (OrderStatusEnum.WAIT_PAY.getCode() == status) {
            orderDetailsVO.setOrderStatus("未支付");
            orderDetailsVO.setPayMethod("未支付");

        } else if (OrderStatusEnum.PAYMENT.getCode() == status) {
            orderDetailsVO.setOrderStatus("已完成");
            orderDetailsVO.setPayMethod(PayMethodEnum.getValue(orderDetailsDTO.getPayType()));
        }

        return orderDetailsVO;
    }

    @Override
    public List<RoughStoneOrder> getCloseOrder() {
        return roughStoneOrderDao.getCloseOrder();
    }

    @Override
    public void autoCloseOrder(RoughStoneOrder order) throws GlobalException {
        Assert.isTrue(roughStoneOrderDao.closeOrder(order.getId()), () -> new GlobalException("关闭订单失败"));
        productStockService.SubFrozenCount(order.getProductId(), order.getCollectionId(), order.getCount());

    }

    @Override
    public Page<RoughStoneOrderVO> orderPageFromAdmin(String orderNo, OrderStatusEnum status, ClassifyType typeClassify, Date startOrderTime, Date endOrderTime, Date startPayTime, Date endPayTime, String userTel, int pageNo, int pageSize) {
        if (status != null && status.getCode() == OrderStatusEnum.ALL.getCode()) {
            //查询全部订单
            status = null;
        }
        return roughStoneOrderDao.orderPageFromAdmin(orderNo, status, typeClassify, startOrderTime, endOrderTime, startPayTime, endPayTime, userTel, pageNo, pageSize);
    }

    @Override
    public List<RoughStoneOrderVO> roughStoneOrderExcel(String orderNo, OrderStatusEnum status, ClassifyType typeClassify, Date startOrderTime, Date endOrderTime, Date startPayTime, Date endPayTime, String userTel) {
        List<RoughStoneOrderVO> roughStoneOrderList = roughStoneOrderDao.roughStoneOrderExcel(orderNo, status, typeClassify, startOrderTime, endOrderTime, startPayTime, endPayTime, userTel);
        roughStoneOrderList.forEach(item -> {
            item.setTypeClassifyText(item.getTypeClassify().getDescription());
            item.setStatusText(item.getStatus().getDescription());
        });
        return roughStoneOrderList;
    }

    @Override
    public Integer countRoughStoneOrder(Long userId) {
        LambdaQueryWrapper<RoughStoneOrder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RoughStoneOrder::getUserId, userId);
        queryWrapper.eq(RoughStoneOrder::getStatus, OrderStatusEnum.PAYMENT);
        queryWrapper.last(" limit 5");
        return roughStoneOrderDao.list(queryWrapper).size();
    }
}